﻿using System;
using System.Collections.Generic;
using System.Linq;
using Xenta.Entities;
using Xenta.Enums;
using Xenta.Security;
using Xenta.Structs;
using Xenta.Utils;

namespace Xenta.Operations
{
    public class ImportLanguagePack : ImportOperation,
        ISecuredOperation
    {
        #region Properties

        public IEnumerable<SecurityPolicy> SecurityPolicies
        {
            get
            {
                yield return new SecurityPolicy()
                    .IsAuthenticated()
                    .HasPermission("GLBLZ");
            }
        }

        #endregion

        #region Utilities

        protected override void Work(IUnitOfWork uow, out int result)
        {
            result = 0;
            if(!Properties.ContainsKey("id"))
                return;

            string merge = Properties["merge"];
            int id = Properties["id"].ParseAs<Int32>();
            var content = Objects.ToDictionary(x => x["key"], x => x["value"]);

            if(merge.Equals("A"))
            {
                uow.Execute(new MergeLanguagePackContent
                {
                    EntityID = id,
                    Content = content,
                    Destination = 'A'
                });
            }
            else if(merge.Equals("B"))
            {
                uow.Execute(new MergeLanguagePackContent
                {
                    EntityID = id,
                    Content = content,
                    Destination = 'B'
                });
            }
            else
            {
                uow.Execute(new SetLanguagePackContent
                {
                    EntityID = id,
                    Content = content
                });
            }
            result = Objects.Count();
        }

        #endregion
    }

    public class ImportLanguagePacks : ImportOperation,
        ISecuredOperation
    {
        #region Properties

        public IEnumerable<SecurityPolicy> SecurityPolicies
        {
            get
            {
                yield return new SecurityPolicy()
                    .IsAuthenticated()
                    .HasPermission("GLBLZ");
            }
        }

        #endregion

        #region Utilities

        protected override void Work(IUnitOfWork uow, out int result)
        {
            result = 0;
            var languages = uow.Execute(new SearchLanguages()).Result;

            foreach(var g in Objects.GroupBy(x => x["code"]))
            {
                foreach(var l in languages)
                {
                    var tmp = g.Where(x => x.ContainsKey(l.Code));
                    if(!tmp.Any())
                        continue;

                    var pack = uow.Execute(new GetLanguagePackByCode
                    {
                        Code = g.Key,
                        LanguageID = l.EntityID
                    }).Result ?? uow.Execute(new CreateLanguagePack
                    {
                        Code = g.Key,
                        LanguageID = l.EntityID,
                    }).Result;
                    if(pack == null)
                        continue;

                    uow.Execute(new SetLanguagePackContent
                    {
                        EntityID = pack.EntityID,
                        Content = tmp.ToDictionary(x => x["key"], x => x[l.Code])
                    });

                    result++;
                }
            }
        }

        #endregion
    }

    public class ImportLanguages : ImportOperation,
        ISecuredOperation
    {
        #region Properties

        public IEnumerable<SecurityPolicy> SecurityPolicies
        {
            get
            {
                yield return new SecurityPolicy()
                    .IsAuthenticated()
                    .HasPermission("GLBLZ");
            }
        }

        #endregion

        #region Utilities

        protected override void Work(IUnitOfWork uow, out int result)
        {
            result = 0;
            foreach(var i in Objects)
            {
                if(!i.ContainsKey("EntityID") ||
                    !i.ContainsKey("Code") ||
                    !i.ContainsKey("Name") ||
                    !i.ContainsKey("Flags"))
                {
                    continue;
                }

                int entityID = i["EntityID"].ParseAs(0);
                string code = i["Code"];
                string name = i["Name"];
                var flags = i["Flags"].ParseAs<LanguageFlags>();
                
                if(entityID != 0)
                {
                    uow.Execute(new UpdateLanguage
                    {
                        EntityID = entityID,
                        Code = code,
                        Name = name,
                        Flags = flags
                    });
                }
                else
                {
                    uow.Execute(new CreateLanguage
                    {
                        Code = code,
                        Name = name,
                        Flags = flags
                    });
                }
                result++;
            }
        }

        #endregion
    }

    public class ImportTimeZones : ImportOperation,
        ISecuredOperation
    {
        #region Properties

        public IEnumerable<SecurityPolicy> SecurityPolicies
        {
            get
            {
                yield return new SecurityPolicy()
                    .IsAuthenticated()
                    .HasPermission("GLBLZ");
            }
        }

        #endregion

        #region Utilities

        protected override void Work(IUnitOfWork uow, out int result)
        {
            result = 0;
            foreach(var i in Objects)
            {
                if(!i.ContainsKey("EntityID") ||
                    !i.ContainsKey("Code") ||
                    !i.ContainsKey("Name") ||
                    !i.ContainsKey("UtcOffset") ||
                    !i.ContainsKey("Flags"))
                {
                    continue;
                }

                int entityID = i["EntityID"].ParseAs(0);
                string code = i["Code"];
                string name = i["Name"];
                int utcOffset = i["UtcOffset"].ParseAs(0);
                var flags = i["Flags"].ParseAs<TimeZoneFlags>();

                if(entityID != 0)
                {
                    uow.Execute(new UpdateTimeZone
                    {
                        EntityID = entityID,
                        Code = code,
                        Name = name,
                        UtcOffset = utcOffset,
                        Flags = flags
                    });
                }
                else
                {
                    uow.Execute(new CreateTimeZone
                    {
                        Code = code,
                        Name = name,
                        UtcOffset = utcOffset,
                        Flags = flags
                    });
                }
                result++;
            }
        }

        #endregion
    }

    public class ImportCurrencies : ImportOperation,
        ISecuredOperation
    {
        #region Properties

        public IEnumerable<SecurityPolicy> SecurityPolicies
        {
            get
            {
                yield return new SecurityPolicy()
                    .IsAuthenticated()
                    .HasPermission("GLBLZ");
            }
        }

        #endregion

        #region Utilities

        protected override void Work(IUnitOfWork uow, out int result)
        {
            result = 0;
            foreach(var i in Objects)
            {
                if(!i.ContainsKey("EntityID") ||
                    !i.ContainsKey("Code") ||
                    !i.ContainsKey("Name") ||
                    !i.ContainsKey("PriceFormat") ||
                    !i.ContainsKey("Rate") ||
                    !i.ContainsKey("Flags"))
                {
                    continue;
                }

                int entityID = i["EntityID"].ParseAs(0);
                string code = i["Code"];
                string name = i["Name"];
                string priceFormat = i["PriceFormat"];
                decimal rate = i["Rate"].ParseAs(Decimal.Zero);
                var flags = i["Flags"].ParseAs<CurrencyFlags>();

                if(entityID != 0)
                {
                    uow.Execute(new UpdateCurrency
                    {
                        EntityID = entityID,
                        Code = code,
                        Name = name,
                        PriceFormat = priceFormat,
                        Rate = rate,
                        Flags = flags
                    });
                }
                else
                {
                    uow.Execute(new CreateCurrency
                    {
                        Code = code,
                        Name = name,
                        PriceFormat = priceFormat,
                        Rate = rate,
                        Flags = flags
                    });
                }
                result++;
            }
        }

        #endregion
    }

    public class ImportMeasureUnits : ImportOperation,
        ISecuredOperation
    {
        #region Properties

        public IEnumerable<SecurityPolicy> SecurityPolicies
        {
            get
            {
                yield return new SecurityPolicy()
                    .IsAuthenticated()
                    .HasPermission("GLBLZ");
            }
        }

        #endregion

        #region Utilities

        protected override void Work(IUnitOfWork uow, out int result)
        {
            result = 0;
            foreach(var i in Objects)
            {
                if(!i.ContainsKey("EntityID") ||
                    !i.ContainsKey("Code") ||
                    !i.ContainsKey("Name") ||
                    !i.ContainsKey("ValueFormat") ||
                    !i.ContainsKey("Ratio") ||
                    !i.ContainsKey("Flags"))
                {
                    continue;
                }

                int entityID = i["EntityID"].ParseAs(0);
                string code = i["Code"];
                string name = i["Name"];
                string valueFormat = i["ValueFormat"];
                decimal ratio = i["Ratio"].ParseAs(Decimal.Zero);
                var flags = i["Flags"].ParseAs<MeasureUnitFlags>();

                if(entityID != 0)
                {
                    uow.Execute(new UpdateMeasureUnit
                    {
                        EntityID = entityID,
                        Code = code,
                        Name = name,
                        ValueFormat = valueFormat,
                        Ratio = ratio,
                        Flags = flags
                    });
                }
                else
                {
                    uow.Execute(new CreateMeasureUnit
                    {
                        Code = code,
                        Name = name,
                        ValueFormat = valueFormat,
                        Ratio = ratio,
                        Flags = flags
                    });
                }
                result++;
            }
        }

        #endregion
    }

    public class ImportCountries : ImportOperation,
        ISecuredOperation
    {
        #region Properties

        public IEnumerable<SecurityPolicy> SecurityPolicies
        {
            get
            {
                yield return new SecurityPolicy()
                    .IsAuthenticated()
                    .HasPermission("GLBLZ");
            }
        }

        #endregion

        #region Utilities

        protected override void Work(IUnitOfWork uow, out int result)
        {
            result = 0;
            foreach(var i in Objects)
            {
                if(!i.ContainsKey("EntityID") ||
                    !i.ContainsKey("Code") ||
                    !i.ContainsKey("Name") ||
                    !i.ContainsKey("TimeFormat") ||
                    !i.ContainsKey("DateFormat") ||
                    !i.ContainsKey("NumericFormat") ||
                    !i.ContainsKey("Flags"))
                {
                    continue;
                }

                int entityID = i["EntityID"].ParseAs(0);
                string code = i["Code"];
                string name = i["Name"];
                string timeFormat = i["TimeFormat"];
                string dateFormat = i["DateFormat"];
                var numericFormat = NumericFormat.Parse(i["NumericFormat"]);
                var flags = i["Flags"].ParseAs<CountryFlags>();

                if(entityID != 0)
                {
                    uow.Execute(new UpdateCountry
                    {
                        EntityID = entityID,
                        Code = code,
                        Name = name,
                        TimeFormat = timeFormat,
                        DateFormat = dateFormat,
                        NumericFormat = numericFormat,
                        Flags = flags
                    });
                }
                else
                {
                    uow.Execute(new CreateCountry
                    {
                        Code = code,
                        Name = name,
                        TimeFormat = timeFormat,
                        DateFormat = dateFormat,
                        NumericFormat = numericFormat,
                        Flags = flags
                    });
                }
                result++;
            }
        }

        #endregion
    }

    public class ImportRegions : ImportOperation,
        ISecuredOperation
    {
        #region Properties

        public IEnumerable<SecurityPolicy> SecurityPolicies
        {
            get
            {
                yield return new SecurityPolicy()
                    .IsAuthenticated()
                    .HasPermission("GLBLZ");
            }
        }

        #endregion

        #region Utilities

        protected override void Work(IUnitOfWork uow, out int result)
        {
            result = 0;
            foreach(var i in Objects)
            {
                if(!i.ContainsKey("EntityID") ||
                    !i.ContainsKey("Country") ||
                    !i.ContainsKey("Code") ||
                    !i.ContainsKey("Name") ||
                    !i.ContainsKey("Flags"))
                {
                    continue;
                }
                
                var country = uow.Execute(new GetCountryByCode
                {
                    Code = i["Country"]
                }).Result;

                if(country == null)
                    continue;

                int entityID = i["EntityID"].ParseAs(0);
                string code = i["Code"];
                string name = i["Name"];
                var flags = i["Flags"].ParseAs<RegionFlags>();


                if(entityID != 0)
                {
                    uow.Execute(new UpdateRegion
                    {
                        EntityID = entityID,
                        CountryID = country.EntityID,
                        Code = code,
                        Name = name,
                        Flags = flags
                    });
                }
                else
                {
                    uow.Execute(new CreateRegion
                    {
                        CountryID = country.EntityID,
                        Code = code,
                        Name = name,
                        Flags = flags
                    });
                }
                result++;
            }
        }

        #endregion
    }

    public class ImportConfigParams : ImportOperation,
        ISecuredOperation
    {
        #region Properties

        public IEnumerable<SecurityPolicy> SecurityPolicies
        {
            get
            {
                yield return new SecurityPolicy()
                    .IsAuthenticated()
                    .HasPermission("SYS");
            }
        }

        #endregion

        #region Utilities

        protected override void Work(IUnitOfWork uow, out int result)
        {
            result = 0;
            uow.Execute(new BulkUpdateConfigParams
            {
                Settings = Objects.ToDictionary(x => x["key"], x => x["value"])
            });
            result = Objects.Count();
        }

        #endregion
    }

    public class ImportRoles : ImportOperation,
        ISecuredOperation
    {
        #region Properties

        public IEnumerable<SecurityPolicy> SecurityPolicies
        {
            get
            {
                yield return new SecurityPolicy()
                    .IsAuthenticated()
                    .HasPermission("ACL");
            }
        }

        #endregion

        #region Utilities

        protected override void Work(IUnitOfWork uow, out int result)
        {
            result = 0;
            foreach(var i in Objects)
            {
                if(!i.ContainsKey("EntityID") ||
                    !i.ContainsKey("Code") ||
                    !i.ContainsKey("Name") ||
                    !i.ContainsKey("Flags") ||
                    !i.ContainsKey("Permissions"))
                {
                    continue;
                }

                int entityID = i["EntityID"].ParseAs(0);
                string code = i["Code"];
                string name = i["Name"];
                var permissionIDs = i["Permissions"].Split(new []
                {
                    ','
                }, StringSplitOptions.RemoveEmptyEntries)
                .Select(x => x.ParseAs<Int32>());
                var flags = i["Flags"].ParseAs<RoleFlags>();
                RoleEntity entity = null;

                if(entityID != 0)
                {
                    entity = uow.Execute(new UpdateRole
                    {
                        EntityID = entityID,
                        Code = code,
                        Name = name,
                        Flags = flags
                    }).Result;
                }
                else
                {
                    entity = uow.Execute(new CreateRole
                    {
                        Code = code,
                        Name = name,
                        Flags = flags
                    }).Result;
                }

                var oldPermissionIDs = entity.Permissions.Select(x => x.EntityID).ToList();

                foreach(var id in oldPermissionIDs.Where(x => !permissionIDs.Contains(x)))
                {
                    uow.Execute(new UnmapPermissionFromRole
                    {
                        EntityID = entity.EntityID,
                        ChildID = id
                    });
                }
                foreach(var id in permissionIDs.Where(x => !oldPermissionIDs.Contains(x)))
                {
                    uow.Execute(new MapPermissionToRole
                    {
                        EntityID = entity.EntityID,
                        ChildID = id
                    });
                }
                result++;
            }
        }

        #endregion
    }

    public class ImportPermissions : ImportOperation,
        ISecuredOperation
    {
        #region Properties

        public IEnumerable<SecurityPolicy> SecurityPolicies
        {
            get
            {
                yield return new SecurityPolicy()
                    .IsAuthenticated()
                    .HasPermission("ACL");
            }
        }

        #endregion

        #region Utilities

        protected override void Work(IUnitOfWork uow, out int result)
        {
            result = 0;
            foreach(var i in Objects)
            {
                if(!i.ContainsKey("EntityID") ||
                    !i.ContainsKey("Code") ||
                    !i.ContainsKey("Name") ||
                    !i.ContainsKey("Flags"))
                {
                    continue;
                }

                int entityID = i["EntityID"].ParseAs(0);
                string code = i["Code"];
                string name = i["Name"];
                var flags = i["Flags"].ParseAs<PermissionFlags>();

                if(entityID != 0)
                {
                    uow.Execute(new UpdatePermission
                    {
                        EntityID = entityID,
                        Code = code,
                        Name = name,
                        Flags = flags
                    });
                }
                else
                {
                    uow.Execute(new CreatePermission
                    {
                        Code = code,
                        Name = name,
                        Flags = flags
                    });
                }
                result++;
            }
        }

        #endregion
    }

    public class ImportMessageTemplates : ImportOperation,
        ISecuredOperation
    {
        #region Properties

        public IEnumerable<SecurityPolicy> SecurityPolicies
        {
            get
            {
                yield return new SecurityPolicy()
                    .IsAuthenticated()
                    .HasPermission("MSG");
            }
        }

        #endregion

        #region Utilities

        protected override void Work(IUnitOfWork uow, out int result)
        {
            result = 0;
            var languages = uow.Execute(new SearchLanguages()).Result;

            foreach(var i in Objects)
            {
                if(!i.ContainsKey("EntityID") ||
                    !i.ContainsKey("Code") ||
                    !i.ContainsKey("SenderID") ||
                    !i.ContainsKey("From") ||
                    !i.ContainsKey("To") ||
                    !i.ContainsKey("BccTo") ||
                    !i.ContainsKey("ReplyTo") ||
                    !i.ContainsKey("Flags"))
                {
                    continue;
                }

                int entityID = i["EntityID"].ParseAs(0);
                string code = i["Code"];
                var senderID = i["SenderID"].ParseAs(Guid.Empty);
                string from = i["From"];
                string to = i["To"];
                string bccTo = i["BccTo"];
                string replyTo = i["ReplyTo"];
                var flags = i["Flags"].ParseAs<MessageTemplateFlags>();
                var tpl = entityID < 0
                    ? uow.Execute(new GetMessageTemplateByCode
                    {
                        Code = code
                    }).Result
                    : null;
                if(tpl != null)
                    entityID = tpl.EntityID;

                if(entityID > 0)
                {
                    tpl = uow.Execute(new UpdateMessageTemplate
                    {
                        EntityID = entityID,
                        Code = code,
                        From = from,
                        To = to,
                        BccTo = bccTo,
                        ReplyTo = replyTo,
                        SenderID = senderID,
                        Flags = flags
                    }).Result;
                }
                else
                {
                    tpl = uow.Execute(new CreateMessageTemplate
                    {
                        Code = code,
                        From = from,
                        To = to,
                        BccTo = bccTo,
                        ReplyTo = replyTo,
                        SenderID = senderID,
                        Flags = flags
                    }).Result;
                }


                foreach(var l in languages)
                {
                    string subjectKey = String.Format("subject({0})", l.Code);
                    if(!i.ContainsKey(subjectKey))
                        continue;

                    string textKey = String.Format("text({0})", l.Code);
                    if(!i.ContainsKey(textKey))
                        continue;

                    uow.Execute(new SaveMessageTemplateTranslation
                    {
                        HolderID = tpl.EntityID,
                        LanguageID = l.EntityID,
                        Subject = i[subjectKey],
                        Text = i[textKey]
                    });
                }

                result++;
            }
        }

        #endregion
    }
}
